using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace WPFTemplateLib.Enhance
{
	/// <summary>
	/// 具有通知功能的字典
	/// <para/>https://www.cnblogs.com/yinyuessh/p/18205333
	/// <para/>已知问题：不支持在 foreach 中修改值。
	/// </summary>
	public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged where TKey : notnull
	{
		private int _index;
		public event NotifyCollectionChangedEventHandler CollectionChanged;
		public event PropertyChangedEventHandler PropertyChanged;

		public new KeyCollection Keys
		{
			get { return base.Keys; }
		}

		public new ValueCollection Values
		{
			get { return base.Values; }
		}

		public new int Count
		{
			get { return base.Count; }
		}

		public new TValue this[TKey key]
		{
			get { return GetValue(key); }
			set { SetValue(key, value); }
		}

		public TValue this[int index]
		{
			get { return GetIndexValue(index); }
			set { SetIndexValue(index, value); }
		}

		public new void Add(TKey key, TValue value)
		{
			base.Add(key, value);
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, FindPair(key), _index));
			OnPropertyChanged(nameof(Keys));
			OnPropertyChanged(nameof(Values));
			OnPropertyChanged(nameof(Count));
		}

		public new void Clear()
		{
			base.Clear();
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			OnPropertyChanged(nameof(Keys));
			OnPropertyChanged(nameof(Values));
			OnPropertyChanged(nameof(Count));
		}

		public new bool Remove(TKey key)
		{
			var pair = FindPair(key);
			if(base.Remove(key))
			{
				OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, pair, _index));
				OnPropertyChanged(nameof(Keys));
				OnPropertyChanged(nameof(Values));
				OnPropertyChanged(nameof(Count));
				return true;
			}
			return false;
		}

		protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
		{
			if(CollectionChanged != null)
			{
				CollectionChanged(this, e);
			}
		}

		protected void OnPropertyChanged(string propertyName)
		{
			if(PropertyChanged != null)
			{
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}

		private TValue GetIndexValue(int index)
		{
			for(int i = 0; i < Count; i++)
			{
				if(i == index)
				{
					var pair = this.ElementAt(i);
					return pair.Value;
				}
			}

			return default;
		}

		private void SetIndexValue(int index, TValue value)
		{
			try
			{
				var pair = this.ElementAtOrDefault(index);
				SetValue(pair.Key, value);
			}
			catch(Exception ex)
			{
				Console.WriteLine($"{ex}");
			}
		}

		private TValue GetValue(TKey key)
		{
			if(ContainsKey(key))
			{
				return base[key];
			}
			else
			{
				return default;
			}
		}

		private void SetValue(TKey key, TValue value)
		{
			if(ContainsKey(key))
			{
				var pair = FindPair(key);
				int index = _index;
				base[key] = value;
				var newpair = FindPair(key);
				OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newpair, pair, index));
				OnPropertyChanged(nameof(Values));
				OnPropertyChanged("Item[]");
			}
			else
			{
				Add(key, value);
			}
		}

		private KeyValuePair<TKey, TValue> FindPair(TKey key)
		{
			_index = 0;
			foreach(var item in this)
			{
				if(item.Key.Equals(key))
				{
					return item;
				}
				_index++;
			}
			return default;
		}

		private int IndexOf(TKey key)
		{
			int index = 0;
			foreach(var item in this)
			{
				if(item.Key.Equals(key))
				{
					return index;
				}
				index++;
			}
			return -1;
		}
	}
}
